using System;
using System.Collections;
using System.Collections.Generic;

namespace Framework
{
    public class BaseTokenReplacer : ITokenReplacer
    {
        private IDictionary KeyValues { get; set; }

        protected BaseTokenReplacer()
        {
            TokenHandlerDelegates = new Dictionary<string, TokenHandler>(FrameworkConstant.DEFAULT_COMPARER_IGNORECASE)
                                {
                                    {"Default", DefaultTokenHandler}
                                };

            TokenHandlerInstances = new Dictionary<string, ITokenHandler>(FrameworkConstant.DEFAULT_COMPARER_IGNORECASE);

            KeyValues = new Hashtable(FrameworkConstant.DEFAULT_COMPARER_IGNORECASE);
        }

        /// <summary>
        /// Token handler delegates as Simple Methods that can produce complex string output
        /// </summary>
        private IDictionary<string, TokenHandler> TokenHandlerDelegates { get; set; }

        /// <summary>
        /// Token handler instance are Instance Classes that implement the ITokenHander interface
        /// and can produce complex string output
        /// </summary>
        /// <remarks>
        /// You can use TokenHandlerDelegates for simple scenarios or instances when you want to maintain
        /// state or access base class accessors
        /// </remarks>
        private IDictionary<string, ITokenHandler> TokenHandlerInstances { get; set; }

        /// <summary>
        /// Adds a Token Handler delegate that will handle Key/Value processing.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="handler">The handler.</param>
        public void AddHandler(string key, TokenHandler handler)
        {
            if (!TokenHandlerDelegates.ContainsKey(key))
            {
                TokenHandlerDelegates.Add(key, handler);
            }
        }

        /// <summary>
        /// Adds a Token Handler istance that will handle Key/Value processing.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="handler">The handler.</param>
        protected void AddHandler(string key, ITokenHandler handler)
        {
            if (!TokenHandlerInstances.ContainsKey(key))
            {
                TokenHandlerInstances.Add(key, handler);
            }
        }

        /// <summary>
        /// Adds a Token Handler istance that will handle Key/Value processing.
        /// </summary>
        /// <param name="key">The key.</param>
        protected void AddHandler<THandlerType>(string key) where THandlerType : ITokenHandler
        {
            var handler = ReflectUtil.CreateInstance<THandlerType>();

            AddHandler(key, handler);
        }

        //public void AddHandler<ITokenHandler>(string key)
        //{
        //    var instance = 
        //    if (!TokenHandlers.ContainsKey(key))
        //    {
        //        TokenHandlers.Add(key, handler);
        //    }
        //}

        /// <summary>
        /// Adds the keys as simple token handlers, its not much different to a dictionary of Key/Values, but instead
        /// it is Keys/KeyValueTokenHandler which just returns the value
        /// </summary>
        public void AddKeyValues(IDictionary keyValues)
        {
            if (keyValues != null)
            {
                foreach (var objectKey in keyValues.Keys)
                {
                    var key = objectKey.ToString();

                    KeyValues.Add(key, keyValues[key]);

                    AddHandler(key, KeyValueTokenHandler);
                }
            }
        }

        /// <summary>
        /// Adds the keys as simple token handlers, its not much different to a dictionary of Key/Values, but instead
        /// it is Keys/KeyValueTokenHandler which just returns the value
        /// </summary>
        /// <remarks>
        /// Why do we do this (extra complexity). It is so that we can combine simple Key/Values with Key/TokenHandlers 
        /// and it is accheived by wrapping the value in side a TokenHandler
        /// </remarks>
        /// <param name="keyValues">The key values.</param>
        public void AddKeyValues(IDictionary<string, string> keyValues)
        {
            if (keyValues != null)
            {
                foreach (var objectKey in keyValues.Keys)
                {
                    var key = objectKey;

                    KeyValues.Add(key, keyValues[key]);

                    AddHandler(key, KeyValueTokenHandler);
                }
            }
        }

        public virtual string GetValue(string key)
        {
            return KeyValues.Contains(key) ? KeyValues[key].ToString() : string.Empty;
        }

        public TokenHandler FindHandler(string key)
        {
            // Look for instance handlers first
            if (TokenHandlerInstances.ContainsKey(key))
            {
                return TokenHandlerInstances[key].Handler;
            }

            // If instance handlers then look for delegate handlers and if no delegate handlers, just use a default handler
            return TokenHandlerDelegates.ContainsKey(key) ? TokenHandlerDelegates[key] : TokenHandlerDelegates["Default"];
        }

        private static string DefaultTokenHandler(string tokenKey, ITokenReplacer tokenReplacer, TokenParameters tokenParamaters)
        {
            return string.Empty;
        }

        private static string KeyValueTokenHandler(string tokenKey, ITokenReplacer tokenReplacer, TokenParameters tokenParamaters)
        {
            return tokenReplacer.GetValue(tokenKey);
        }
    }
}